﻿using System;

namespace net.xBei.Helper; 
/// <summary>
/// 数值相关操作
/// </summary>
public static class NumericHelper {
    /// <summary>
    /// 数字转字符串
    /// </summary>
    /// <param name="num"></param>
    /// <param name="radix"></param>
    /// <returns></returns>
    public static string ToString(this float num, int radix) {
        var s = $"{num}".Split(".", StringSplitOptions.RemoveEmptyEntries);
        if (s.Length <= 1) return s[0];
        return $"{s[0]}.{s[1].Substring(0, Math.Min(radix, s[1].Length))}";
    }

    #region 字符串转数字
    #region 整形
    /// <summary>
    /// 字符串转无符号整形（32位）
    /// </summary>
    /// <param name="txt"></param>
    /// <param name="dv"></param>
    /// <returns></returns>
    public static uint GetUInt(this string txt, uint dv = 0)
        => uint.TryParse(txt, out var r) ? r : dv;
    /// <summary>
    /// 字符串转整形（32位）
    /// </summary>
    /// <param name="txt"></param>
    /// <param name="dv"></param>
    /// <returns></returns>
    public static int GetInt(this string txt, int dv = 0)
        => int.TryParse(txt, out var r) ? r : dv;
    /// <summary>
    /// 对象转整形（32位）
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="dv"></param>
    /// <returns></returns>
    public static int GetInt(this object obj, int dv = 0) {
        if (obj == null) return dv;
        if (obj is string str) {
            return int.TryParse(str, out var r) ? r : dv;
        }
        if (obj is uint uintObj) {
            return (int)uintObj;
        }
        if (obj is int intObj) {
            return intObj;
        }
        if (obj is ulong ulongObj) {
            return (int)ulongObj;
        }
        if (obj is long longObj) {
            return (int)longObj;
        }
        if (obj is float floatObj) {
            return (int)floatObj;
        }
        if (obj is double doubleObj) {
            return (int)doubleObj;
        }
        if (obj is decimal decimalObj) {
            return (int)decimalObj;
        }
        return dv;
    }
    /// <summary>
    /// 字符串转无符号整形（64位）
    /// </summary>
    /// <param name="txt"></param>
    /// <param name="dv"></param>
    /// <returns></returns>
    public static ulong GetULong(this string txt, ulong dv = 0)
        => ulong.TryParse(txt, out var r) ? r : dv;
    /// <summary>
    /// 字符串转整形（64位）
    /// </summary>
    /// <param name="txt"></param>
    /// <param name="dv"></param>
    /// <returns></returns>
    public static long GetLong(this string txt, long dv = 0)
        => long.TryParse(txt, out var r) ? r : dv;
    /// <summary>
    /// 对象转整形（64位）
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="dv"></param>
    /// <returns></returns>
    public static long GetLong(this object obj, long dv = 0) {
        if (obj == null) return dv;
        if (obj is string str) {
            return long.TryParse(str, out var r) ? r : dv;
        }
        if (obj is uint uintObj) {
            return (long)uintObj;
        }
        if (obj is int intObj) {
            return intObj;
        }
        if (obj is ulong ulongObj) {
            return (long)ulongObj;
        }
        if (obj is long longObj) {
            return longObj;
        }
        if (obj is float floatObj) {
            return (long)floatObj;
        }
        if (obj is double doubleObj) {
            return (long)doubleObj;
        }
        if (obj is decimal decimalObj) {
            return (long)decimalObj;
        }
        return dv;
    }
    #endregion
    #region 浮点
    /// <summary>
    /// 字符串转浮点（32位）
    /// </summary>
    /// <param name="txt"></param>
    /// <param name="dv"></param>
    /// <returns></returns>
    public static float GetFloat(this string txt, float dv = 0)
        => float.TryParse(txt, out var r) ? r : dv;
    /// <summary>
    /// 字符串转浮点（64位）
    /// </summary>
    /// <param name="txt"></param>
    /// <param name="dv"></param>
    /// <returns></returns>
    public static double GetDouble(this string txt, double dv = 0)
        => double.TryParse(txt, out var r) ? r : dv;
    /// <summary>
    /// 字符串转浮点（128位）
    /// </summary>
    /// <param name="txt"></param>
    /// <param name="dv"></param>
    /// <returns></returns>
    public static decimal GetDecimal(this string txt, decimal dv = 0)
        => decimal.TryParse(txt, out var r) ? r : dv;
    /// <summary>
    /// 对象转浮点（128位，16个字节）
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="dv"></param>
    /// <returns></returns>
    public static decimal GetDecimal(this object obj, decimal dv = 0) {
        if (obj == null) return dv;
        if (obj is string str) {
            return decimal.TryParse(str, out var r) ? r : dv;
        }
        if (obj is uint uintObj) {
            return (decimal)uintObj;
        }
        if (obj is int intObj) {
            return (decimal)intObj;
        }
        if (obj is ulong ulongObj) {
            return (decimal)ulongObj;
        }
        if (obj is long longObj) {
            return (decimal)longObj;
        }
        if (obj is float floatObj) {
            return (decimal)floatObj;
        }
        if (obj is double doubleObj) {
            return (decimal)doubleObj;
        }
        if (obj is decimal decimalObj) {
            return decimalObj;
        }
        return dv;
    }
    #endregion
    #endregion
    #region 位运算
    /// <summary>
    /// 是否包含指定标志
    /// </summary>
    /// <param name="num"></param>
    /// <param name="flag"></param>
    /// <returns></returns>
    public static bool HasFlag(this int num, int flag) => (num & flag) == flag;
    #endregion
    /// <summary>
    /// 是否是整数（没有小数点）
    /// </summary>
    /// <param name="num"></param>
    /// <returns></returns>
    public static bool IsInteger(this double num) => num == (int)num;
    /// <summary>
    /// 是否不是整数（有小数点）
    /// </summary>
    /// <param name="num"></param>
    /// <returns></returns>
    public static bool IsNotInteger(this double num) => num != (int)num;

    #region 中国版的四舍五入
    /// <summary>
    /// 中国版的四舍五入
    /// </summary>
    /// <param name="num"></param>
    /// <param name="radix"></param>
    /// <returns></returns>
    public static decimal Round(this decimal num, int radix = 2) => decimal.Round(num, radix, MidpointRounding.AwayFromZero);
    /// <summary>
    /// 中国版的四舍五入
    /// </summary>
    /// <param name="num"></param>
    /// <param name="radix"></param>
    /// <returns></returns>
    public static decimal? Round(this decimal? num, int radix = 2) => num.HasValue ? decimal.Round(num.Value, radix, MidpointRounding.AwayFromZero) : num;
    /// <summary>
    /// 中国版的四舍五入
    /// </summary>
    /// <param name="num"></param>
    /// <param name="radix"></param>
    /// <returns></returns>
    public static double Round(this double num, int radix = 2) => (double)Round((decimal)num, radix);
    /// <summary>
    /// 中国版的四舍五入
    /// </summary>
    /// <param name="num"></param>
    /// <param name="radix"></param>
    /// <returns></returns>
    public static float Round(this float num, int radix = 2) => (float)Round((decimal)num, radix);
    #endregion
    #region System.Math
    /// <summary>
    /// 返回大于或等于指定数字的最小整数值。<see cref="Math.Ceiling(double)"/>
    /// </summary>
    /// <param name="v"></param>
    /// <returns></returns>
    public static double Ceiling(this double v) => Math.Ceiling(v);
    /// <summary>
    /// 返回大于或等于指定数字的最小整数值。<see cref="Math.Ceiling(double)"/>
    /// </summary>
    /// <param name="v"></param>
    /// <returns></returns>
    public static double? Ceiling(this double? v) => v.HasValue ? Math.Ceiling(v.Value) : v;
    /// <summary>
    /// 返回大于或等于指定数字的最小整数值。<see cref="Math.Ceiling(decimal)"/>
    /// </summary>
    /// <param name="v"></param>
    /// <returns></returns>
    public static decimal Ceiling(this decimal v) => Math.Ceiling(v);
    /// <summary>
    /// 返回大于或等于指定数字的最小整数值。<see cref="Math.Ceiling(decimal)"/>
    /// </summary>
    /// <param name="v"></param>
    /// <returns></returns>
    public static decimal? Ceiling(this decimal? v) => v.HasValue ? Math.Ceiling(v.Value) : v;
    #endregion
}
